#include "ShaderCompileSubsystem.h"
#include <shaderc/shaderc.hpp>
#include <memory>
#include <bit>
//#include "ShaderIncluder.h"

#include "Containers/String8.h"

static shaderc::Compiler Compiler;
static shaderc::CompileOptions Options;

void RShaderCompileSubsystem::Initialize()
{
    //Options.SetIncluder(std::make_unique<CShaderIncluder>());
}

RShaderCompileSubsystem::SCompileResult RShaderCompileSubsystem::Compile(const CString &Text, EShaderStage InType)
{
    SCompileResult Ret;

    shaderc_shader_kind Kind;
    switch(InType)
    {
        case EShaderStage::Vertex:
            Kind=shaderc_vertex_shader;
            break;

        case EShaderStage::Fragment:
            Kind=shaderc_fragment_shader;
            break;

        default:
            assert(false&& "Unimplement");

    }

    CString8 Text8=Text.ToUtf8String();
    shaderc::SpvCompilationResult module = Compiler.CompileGlslToSpv(
      Text8.CStr(), Text8.CStrLength(), Kind, "templteShader", Options);    

    if (module.GetCompilationStatus() !=shaderc_compilation_status_success) 
    {
        Ret.ErrorMessage=CString((const char8_t*)module.GetErrorMessage().c_str());
        return Ret;
    }

    Ret.ByteCode.Reserve((module.end()-module.begin()) * sizeof(uint32_t) );

    if constexpr(std::endian::native == std::endian::little)
    {
        for(auto It=module.begin();It!=module.end();It++)
        {
            Ret.ByteCode.Add((*It));
            Ret.ByteCode.Add((*It) >> 8 );
            Ret.ByteCode.Add((*It) >> 16 );
            Ret.ByteCode.Add((*It) >> 24 );
        }
    }
    else
    {
        for(auto It=module.begin();It!=module.end();It++)
        {
            Ret.ByteCode.Add((*It) >> 24 );
            Ret.ByteCode.Add((*It) >> 16 );
            Ret.ByteCode.Add((*It) >> 8 );
            Ret.ByteCode.Add((*It));
        }        
    }


    return Ret;
}
